package org.ttjhome.db;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.hibernate.StaleStateException;
import org.ttjhome.db.dbo.Activity;
import org.ttjhome.db.dbo.ActivityRecord;
import org.ttjhome.db.dbo.Activity_;
import org.ttjhome.db.dbo.Candidate;
import org.ttjhome.db.dbo.Candidate_;
import org.ttjhome.db.dbo.Company;
import org.ttjhome.db.dbo.Company_;
import org.ttjhome.db.dbo.Job;
import org.ttjhome.db.dbo.Job_;
import org.ttjhome.db.dbo.Resume;
import org.ttjhome.db.dbo.Tag;
import org.ttjhome.html.struts.common.ActivityStatus;
import org.ttjhome.html.struts.common.CandidateCriteria;

public final class HunterDAO {
	
	

	public Candidate saveOrUpdateCandidate(Candidate candidate) {
		Candidate result;
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			if (candidate.getId() == null) {
				entityManager.persist(candidate);
				result = candidate;
			} else {
				result = entityManager.merge(candidate);
			}
		} catch (StaleStateException e) {
			throw e;
		}
		return result;
	}

	public int getCandidateCount(CandidateCriteria criteria) {
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			CriteriaQuery<Candidate> criteriaQuery = CandidateCriteriaHelper
					.getCandidateQuery(entityManager, criteria);
			TypedQuery<Candidate> query = entityManager.createQuery(criteriaQuery); 
			List<Candidate> result = query.getResultList();
			return result.size();


		} catch (StaleStateException e) {
			throw e;
		}
		
	}
	
	public List<Candidate> getCandidates(CandidateCriteria criteria) {
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			CriteriaQuery<Candidate> criteriaQuery = CandidateCriteriaHelper
					.getCandidateQuery(entityManager, criteria);
			TypedQuery<Candidate> query = entityManager.createQuery(criteriaQuery); 
			List<Candidate> result = query.getResultList();
			return result;


		} catch (StaleStateException e) {
			throw e;
		}
		
	}
	
	public List<Tag> getGroupedTag(){
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
//			CriteriaQuery<Tag> criteriaQuery = CandidateCriteriaHelper
//					.groupAllCandidateTags(entityManager);
			Query query = CandidateCriteriaHelper
					.groupAllCandidateTags(entityManager);
//			TypedQuery<Tag> query = entityManager.createQuery(criteriaQuery); 
			List results = query.getResultList();
			List<Tag> tags = new ArrayList<Tag>();
			for(Iterator iter=results.iterator();iter.hasNext();){
				Object[] result = (Object[]) iter.next();
				Tag tag = new Tag();
				tag.setTag((String) result[0]);
				tag.setCount(((Number) result[1]).longValue());
				tags.add(tag);
			}
			
		return tags;

		} catch (StaleStateException e) {
			throw e;
		}
		
	}

	public Candidate getCandidate(Long candidateId) {
		if(candidateId==null)
			throw new IllegalArgumentException("candidate id can not be null");
		EntityManager entityManager =  DbThreadLocal.getInstance().getThreadsBlackboard();
		try {
			Candidate candidate = entityManager.find(
					Candidate.class, candidateId);
			return candidate;
		} catch (RuntimeException ex) {
			throw ex;
		}
	}

	public List<Tag> getAllTags() {
		EntityManager entityManager =  DbThreadLocal.getInstance().getThreadsBlackboard();
		try {
			CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
			CriteriaQuery<Tag> criteriaQuery = criteriaBuilder
					.createQuery(Tag.class);
			Root<Tag> tag = criteriaQuery.from(Tag.class);
			TypedQuery<Tag> query = entityManager.createQuery(criteriaQuery); 
			List<Tag> result = query.getResultList();
			return result;

			
		} catch (RuntimeException ex) {
			throw ex;
		}
	}

	public Resume getResume(String resumeId) {
		Resume result;
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			result= entityManager.find(Resume.class,
					Long.valueOf(resumeId));
		} catch (RuntimeException e) {
			throw e;
		}
		return result;
	}
	
	public Tag saveTag(Tag tag) {
		Tag result;
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			if (tag.getId() == null) {
				entityManager.persist(tag);
				result = tag;
			} else {
				result = entityManager.merge(tag);
			}
		} catch (StaleStateException e) {
			throw e;
		}
		return result;
	}

	public void deleteResume(Resume resume) {
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			resume = entityManager.merge(resume);
			resume.getCandidate().getResumes().remove(resume);
			entityManager.remove(resume);
			entityManager.flush();
		} catch (StaleStateException e) {
			throw e;
		}

	}

	public List<Company> getCompanies() {
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
			CriteriaQuery<Company> criteriaQuery = criteriaBuilder
					.createQuery(Company.class);
			//has to have this line
			Root<Company> company = criteriaQuery.from(Company.class);
			TypedQuery<Company> query = entityManager.createQuery(criteriaQuery); 
			List<Company> result = query.getResultList();
			return result;
		} catch (StaleStateException e) {
			throw e;
		}
	}

	public Company saveOrUpdateCompany(Company company) {
		Company result;
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			if (company.getId() == null) {
				entityManager.persist(company);
				result = company;
			} else {
				result = entityManager.merge(company);
			}
		} catch (StaleStateException e) {
			throw e;
		}
		return result;
	}

	public Company getCompany(Long companyId) {
		if(companyId==null)
			throw new IllegalArgumentException("company id can not be null");
		EntityManager entityManager =  DbThreadLocal.getInstance().getThreadsBlackboard();
		try {
			Company company = entityManager.find(
					Company.class, companyId);
			return company;
		} catch (RuntimeException ex) {
			throw ex;
		}
	}

	public List<Job> getJobsByCompanyId(String companyId) {
		EntityManager entityManager = DbThreadLocal.getInstance()
				.getThreadsBlackboard();
		try {
			CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
			CriteriaQuery<Job> criteriaQuery = criteriaBuilder
					.createQuery(Job.class);
			Root<Job> job = criteriaQuery.from(Job.class);
			Join< Job, Company> join = job.join(Job_.company);
			Predicate predicate=null;
			if(companyId!=null)
				predicate= criteriaBuilder.equal(join.get(Company_.id), Long.valueOf(companyId));
			if(predicate!=null)
				criteriaQuery.where(predicate);
			TypedQuery<Job> query = entityManager.createQuery(criteriaQuery); 
			List<Job> result = query.getResultList();
			return result;


		} catch (StaleStateException e) {
			throw e;
		}
		
	}

	public Job saveOrUpdateJob(Job job) {
		Job result;
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			if (job.getId() == null) {
				entityManager.persist(job);
				result = job;
			} else {
				result = entityManager.merge(job);
			}
		} catch (StaleStateException e) {
			throw e;
		}
		return result;
	}

	public Job getJob(Long id) {
		if(id==null)
			throw new IllegalArgumentException("job id can not be null");
		EntityManager entityManager =  DbThreadLocal.getInstance().getThreadsBlackboard();
		try {
			Job job = entityManager.find(
					Job.class, id);
			return job;
		} catch (RuntimeException ex) {
			throw ex;
		}
	}

	public Activity saveOrUpdateActivity(Activity activity) {
		Activity result;
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			if (activity.getId() == null) {
				entityManager.persist(activity);
				result = activity;
			} else {
				result = entityManager.merge(activity);
			}
		} catch (StaleStateException e) {
			throw e;
		}
		return result;
	}
	
	
	

	public ActivityRecord saveOrUpdateActivityRecord(ActivityRecord record) {
		ActivityRecord result;
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			if (record.getId() == null) {
				entityManager.persist(record);
				result = record;
				record.getActivity().getRecords().add(record);
			} else {
				result = entityManager.merge(record);
			}
			entityManager.merge(record.getActivity());
		} catch (StaleStateException e) {
			throw e;
		}
		return result;
	}

	public List<Activity> getActivitiesByCandidate(Candidate candidate) {
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
			.getThreadsBlackboard();
			CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
			CriteriaQuery<Activity> criteriaQuery = criteriaBuilder
					.createQuery(Activity.class);
			Root<Activity> activity = criteriaQuery.from(Activity.class);
			Join< Activity, Candidate> join = activity.join(Activity_.candidate);
			Predicate predicate=null;
			if(candidate!=null)
				predicate= criteriaBuilder.equal(join.get(Candidate_.id), candidate.getId());
			
			if(predicate!=null)
				criteriaQuery.where(predicate);
			TypedQuery<Activity> query = entityManager.createQuery(criteriaQuery); 
			List<Activity> result = query.getResultList();
			return result;
		} catch (StaleStateException e) {
			throw e;
		}
		
	}

	public Activity getActivity(Long activityId){
		if(activityId==null)
			throw new IllegalArgumentException("activity id can not be null");
		EntityManager entityManager =  DbThreadLocal.getInstance().getThreadsBlackboard();
		try {
			Activity activity = entityManager.find(
					Activity.class, activityId);
			return activity;
		} catch (RuntimeException ex) {
			throw ex;
		}
	}
	
	public void closeActivity(Activity activity) {
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
					.getThreadsBlackboard();
			activity.setStatus(ActivityStatus.Closed.name());
			activity = entityManager.merge(activity);
			entityManager.flush();
		} catch (StaleStateException e) {
			throw e;
		}

		
	}

	public List<Activity> getActivitiesByJob(Job job) {
		try {
			EntityManager entityManager = DbThreadLocal.getInstance()
			.getThreadsBlackboard();
			CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
			CriteriaQuery<Activity> criteriaQuery = criteriaBuilder
					.createQuery(Activity.class);
			Root<Activity> activity = criteriaQuery.from(Activity.class);
			Join< Activity, Job> join = activity.join(Activity_.job);
			Predicate predicate=null;
			if(job!=null)
				predicate= criteriaBuilder.equal(join.get(Job_.id), job.getId());
			if(predicate!=null)
				criteriaQuery.where(predicate);
			TypedQuery<Activity> query = entityManager.createQuery(criteriaQuery); 
			List<Activity> result = query.getResultList();
			return result;
		} catch (StaleStateException e) {
			throw e;
		}
	}



}
